package io.renren.modules.medicine.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import io.renren.common.constant.Constant;
import io.renren.common.interceptor.DataScope;
import io.renren.common.service.impl.CrudServiceImpl;
import io.renren.common.utils.JsonUtils;
import io.renren.common.validator.ValidatorUtils;
import io.renren.common.validator.group.AddGroup;
import io.renren.common.validator.group.DefaultGroup;
import io.renren.modules.medicine.dao.TaskBiologicalVisualizationDao;
import io.renren.modules.medicine.dto.TaskBiologicalVisualizationDTO;
import io.renren.modules.medicine.entity.TaskBiologicalVisualizationEntity;
import io.renren.modules.medicine.enums.TaskStatusEnum;
import io.renren.modules.medicine.service.TaskBiologicalVisualizationService;
import io.renren.modules.security.user.SecurityUser;
import io.renren.modules.security.user.UserDetail;
import io.renren.modules.sys.service.SysDeptService;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.Map;

/**
 * 生物数据可视化
 *
 * @author sheliming shelimingming@qq.com
 * @since 1.0.0 2023-01-13
 */
@Service
public class TaskBiologicalVisualizationServiceImpl extends CrudServiceImpl<TaskBiologicalVisualizationDao, TaskBiologicalVisualizationEntity, TaskBiologicalVisualizationDTO> implements TaskBiologicalVisualizationService {

    @Autowired
    private SysDeptService sysDeptService;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Override
    public QueryWrapper<TaskBiologicalVisualizationEntity> getWrapper(Map<String, Object> params) {
        String id = (String) params.get("id");

        QueryWrapper<TaskBiologicalVisualizationEntity> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.isNotBlank(id), "id", id);
        wrapper.select(TaskBiologicalVisualizationEntity.class, info -> !info.getColumn().equals("dataset")
                && !info.getColumn().equals("result"));

        String beginTimeString = (String) params.get(Constant.BEGIN_TIME);
        wrapper.ge(StringUtils.isNotBlank(beginTimeString), "create_date", beginTimeString);
        String endTimeString = (String) params.get(Constant.END_TIME);
        wrapper.le(StringUtils.isNotBlank(endTimeString), "create_date", endTimeString);

        if (params.get(Constant.SQL_FILTER) != null) {
            wrapper.apply(params.get(Constant.SQL_FILTER) != null, ((DataScope) params.get(Constant.SQL_FILTER)).getSqlFilter());
        }

        return wrapper;
    }


    @Override
    public void train(String datasetString, String traniningParams) {
        TaskBiologicalVisualizationDTO dto = new TaskBiologicalVisualizationDTO();
        dto.setDataset(datasetString);
        dto.setTraniningParams(traniningParams);

        UserDetail user = SecurityUser.getUser();
        dto.setCreator(user.getId());
        dto.setCreatorName(user.getRealName());
        dto.setUpdater(user.getId());
        dto.setDeptId(user.getDeptId());
        if (user.getDeptId() != null) {
            dto.setDeptName(sysDeptService.get(user.getDeptId()).getName());
        }
        dto.setCreateDate(new Date());
        dto.setUpdateDate(new Date());
        dto.setStatus(TaskStatusEnum.CREATED.value());
        //效验数据
        ValidatorUtils.validateEntity(dto, AddGroup.class, DefaultGroup.class);

        this.save(dto);

        sendTrainMQ(dto.getId(), datasetString, traniningParams);

        dto.setStatus(TaskStatusEnum.RUNNING.value());
        this.update(dto);
    }

    @Override
    public String explan(Long taskId, String explanationParams) {
        TaskBiologicalVisualizationDTO dto = this.get(taskId);
        dto.setExplanationParams(explanationParams);
        dto.setStatus(TaskStatusEnum.EXPLANING.value());
        this.update(dto);

        sendExplanMQ(dto.getId(), dto.getModelUrl(), explanationParams);

        int time = 60;
        while (true) {
            dto = this.get(taskId);
            if (TaskStatusEnum.DONE.value().equals(dto.getStatus())) {
                return dto.getResult();
            }
            try {
                Thread.sleep(1000);
                time--;
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            if (time <= 0) {
                return "";
            }
        }
    }

    private void sendTrainMQ(Long id, String datasetString, String traniningParams) {
        TrainMQBody trainMqBody = new TrainMQBody();
        trainMqBody.setTaskId(id);
        trainMqBody.setDataset(datasetString);
        trainMqBody.setTraniningParams(traniningParams);

        rabbitTemplate.convertAndSend("biological_visualization_exchange", "biological_visualization_train.hh", JsonUtils.toJsonString(trainMqBody));
    }

    @Data
    private class TrainMQBody {
        private Long taskId;
        private String dataset;
        private String traniningParams;
    }

    private void sendExplanMQ(Long id, String modelUrl, String explanationParams) {
        ExplanMQBody explanMQBody = new ExplanMQBody();
        explanMQBody.setTaskId(id);
        explanMQBody.setModelUrl(modelUrl);
        explanMQBody.setExplanationParams(explanationParams);

        rabbitTemplate.convertAndSend("biological_visualization_exchange", "biological_visualization_explan.hh", JsonUtils.toJsonString(explanMQBody));
    }

    @Data
    private class ExplanMQBody {
        private Long taskId;
        private String modelUrl;
        private String explanationParams;
    }
}